<script setup lang="ts">
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { onMounted } from 'vue';

const ThreeObj = {} as IThreeObj

const width = window.innerWidth
const height = window.innerHeight

/* Rubik.js 第4行至第14行 */
const BasicParams = {
    x: 0,
    y: 0,
    z: 0,
    num: 3,
    len: 50,
    //右、左、上、下、前、后
    colors: ['#ff6b02', '#dd422f',
        '#ffffff', '#fdcd02',
        '#3d81f7', '#019d53']
};


/* Rubik.js 第61行至第78行 */
function faces(rgbaColor: string) {
    const canvas = document.createElement('canvas');
    canvas.width = 256;
    canvas.height = 256;
    const context = canvas.getContext('2d');
    //画一个宽高都是256的黑色正方形
    context!.fillStyle = 'rgba(0,0,0,1)';
    context!.fillRect(0, 0, 256, 256);
    //在内部用某颜色的16px宽的线再画一个宽高为224的圆角正方形并用改颜色填充
    context!.rect(16, 16, 224, 224);
    context!.lineJoin = 'round';
    context!.lineWidth = 16;
    context!.fillStyle = rgbaColor;
    context!.strokeStyle = rgbaColor;
    context!.stroke();
    context!.fill();
    return canvas;
}

const SimpleCube = (x: number, y: number, z: number, num: number, len: number) => {
    //魔方左上角坐标
    const leftUpX = x - (num / 2) * len;
    const leftUpY = y + (num / 2) * len;
    const leftUpZ = z + (num / 2) * len;

    const cubes = [];
    for (let i = 0; i < num; i++) {
        for (let j = 0; j < num * num; j++) {

            const myFaces = [];
            for (let k = 0; k < 6; k++) {
                myFaces[k] = faces(BasicParams.colors[k]);
            }

            const materials = [];
            for (let k = 0; k < 6; k++) {
                const texture = new THREE.Texture(myFaces[k]);
                texture.needsUpdate = true;
                materials.push(new THREE.MeshLambertMaterial({ map: texture }));
            }

            const cubegeo = new THREE.BoxGeometry(len, len, len);
            const cube = new THREE.Mesh(cubegeo, materials);

            //依次计算各个小方块中心点坐标
            cube.position.x = leftUpX + (j % num) * len;
            cube.position.y = leftUpY - Math.floor(j / num) * len;
            cube.position.z = leftUpZ - i * len;
            cube.name = `box${i}`
            cubes.push(cube)
        }
    }
    return cubes;
}



const createBox = () => {
    const boxs = SimpleCube(BasicParams.x, BasicParams.y, BasicParams.z, BasicParams.num, BasicParams.len)
    return boxs
}

const createCamera = () => {
    const camera = new THREE.PerspectiveCamera(75, width / height, 1, 1000)
    camera.position.set(200, 200, 200)
    camera.lookAt(0, 0, 0)
    ThreeObj.camera = camera
}

const createRenderer = () => {
    const renderer = new THREE.WebGLRenderer({
        antialias: true,
    })
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.setClearColor(0x000000)
    renderer.setSize(width, height)
    document.getElementById('three')?.appendChild(renderer.domElement)
    ThreeObj.renderer = renderer
}

const createLight = () => {
    const ambient = new THREE.AmbientLight(0xffffff)
    const deriction = new THREE.DirectionalLight(0xffffff, 1)
    deriction.position.set(100, 200, 50)
    ThreeObj.ambient = ambient
    ThreeObj.deriction = deriction
}

const createScene = () => {
    createCamera()
    createRenderer()
    createLight()
}

const initScene = () => {
    const scene = new THREE.Scene()
    const boxs = createBox()
    boxs.forEach(box => {
        scene.add(box)
    })
    scene.add(ThreeObj.ambient)
    scene.add(ThreeObj.deriction)
    ThreeObj.scene = scene
}

const render = () => {
    initScene()
    ThreeObj.renderer.render(ThreeObj.scene, ThreeObj.camera)
    const orbitControls = new OrbitControls(ThreeObj.camera, ThreeObj.renderer.domElement)
    // 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
    orbitControls.addEventListener('change', function () {
        ThreeObj.renderer.render(ThreeObj.scene, ThreeObj.camera)
    });//监听鼠标、键盘事件
}

// const raycaster = new THREE.Raycaster();
// const pointer = new THREE.Vector2();
window.addEventListener('mousedown', (event) => {
    // pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
    // pointer.y = - (e.clientY / window.innerHeight) * 2 + 1;
    // raycaster.setFromCamera(pointer, ThreeObj.camera);

    // const intersects = raycaster.intersectObjects(ThreeObj.scene.children);

    // console.log(intersects[0])
    //获取到浏览器坐标
    const x = (event.clientX / window.innerWidth) * 2 - 1
    const y = -(event.clientY / window.innerHeight) * 2 + 1
    // console.log(x, y)

    //创建三维设备坐标
    const standardVector = new THREE.Vector3(x, y, 0.5)
    // console.log(standardVector)

    //转化为世界坐标
    const worldVector = standardVector.unproject(ThreeObj.camera)

    //序列化
    const ray = worldVector.sub(ThreeObj.camera.position).normalize()

    //实现点击选中
    //创建一条射线发射器
    const raycaster = new THREE.Raycaster(ThreeObj.camera.position, ray)

    //返回射线碰撞到的物体
    const intersects = raycaster.intersectObjects(ThreeObj.scene.children, true)
    console.log(intersects, '点击')
})

onMounted(() => {
    createScene()
    render()
})
</script>

<template>
    <div id="three"></div>
</template>